﻿using System.Collections.Generic;
using IcicleFramework.Components.Actions.ActionEffects;
using IcicleFramework.Entities;

namespace IcicleFramework.Components.Actions
{
    public delegate void OnStartedPerformingActionsHandler(IAction action, IGameObject target, bool continuous);

    public delegate void OnStoppedPerformingActionsHandler(IAction action, int numActionsPerformedThisTime);

    public interface IActionComponent : IBaseComponent
    {
        /// <summary>
        /// Gets the <see cref="IAction"/>s performed by this IActionComponent.
        /// </summary>
        IEnumerator<IAction> Actions { get; }

        /// <summary>
        /// Gets the <see cref="IActionEffect"/>s applied to this IActionComponent.
        /// </summary>
        IEnumerator<IActionEffect> AttachedActionEffects { get; }
        
        /// <summary>
        /// An event that is fired when an <see cref="IAction"/> within this <see cref="IActionComponent"/> begins performing actions.
        /// </summary>
        event OnStartedPerformingActionsHandler OnStartedPerformingActions;

        /// <summary>
        /// An event that is fired when an <see cref="IAction"/> within this <see cref="IActionComponent"/> stops performing actions.
        /// </summary>
        event OnStoppedPerformingActionsHandler OnStoppedPerformingActions;

        /// <summary>
        /// Begins performing at least one execution of this <see cref="IActionComponent"/>s <see cref="IAction"/> targeted at the given <see cref="IGameObject"/>.
        /// </summary>
        /// <param name="target">The <see cref="IGameObject"/> target for the action(s).</param>
        /// <param name="actionName">The name of the <see cref="IAction"/> to perform.</param>
        /// <param name="data">Any data necessary for the execution of the action.</param>
        /// <param name="continuous">Optional parameter where, if true, this <see cref="IActionComponent"/> will continuously perform an action.
        /// If false (default) only a single execution of an action will occur.</param>
        /// <returns>True if the action was started, false if otherwise.</returns>
        bool StartPerformingAction(IGameObject target, string actionName, IActionData data = null, bool continuous = false);

        /// <summary>
        /// Stops the given <see cref="IAction"/> from performing its actions.
        /// </summary>
        /// <param name="actionName">The name of the <see cref="IAction"/> to halt.</param>
        void StopPerformingAction(string actionName);

        /// <summary>
        /// Pauses the given <see cref="IAction"/> from performing it's actions and retains its state for resuming purposes.
        /// </summary>
        /// <param name="actionName">The name of the <see cref="IAction"/> to pause.</param>
        void PausePerformingAction(string actionName);

        /// <summary>
        /// Resumes the given <see cref="IAction"/> at the current state it was in previously.
        /// </summary>
        /// <param name="actionName">The name of the <see cref="IAction"/> to resume.</param>
        void ResumePerformingAction(string actionName);

        /// <summary>
        /// Stops any further execution of all <see cref="IAction"/>s.
        /// </summary>
        void StopPerfomingActions();

        /// <summary>
        /// Pauses all <see cref="IAction"/>s being executed and retains the state for resuming purposes.
        /// </summary>
        void PausePerformingActions();

        /// <summary>
        /// Resumes all paused <see cref="IAction"/>s at the current state they were in previously.
        /// </summary>
        void ResumePerformingActions();

        /// <summary>
        /// Requests that the given <see cref="IActionEffect"/> be attached to this <see cref="IActionComponent"/>, which will then apply its actions.
        /// </summary>
        /// <param name="actionEffect">The <see cref="IActionEffect"/> to attach.</param>
        /// <returns>True if the <see cref="IActionEffect"/> could be attached, false if otherwise.</returns>
        bool AttachActionEffect(IActionEffect actionEffect);

        /// <summary>
        /// Requests that the given <see cref="IActionEffect"/> from this <see cref="IActionComponent"/>.
        /// </summary>
        /// <param name="actionEffect">The <see cref="IActionEffect"/> to detach.</param>
        /// <returns>True if this <see cref="IActionEffect"/> could be detached, false if otherwise.</returns>
        bool DetachActionEffect(IActionEffect actionEffect);

        /// <summary>
        /// Requests that all <see cref="IActionEffect"/>s be detached, if possible.
        /// </summary>
        /// <param name="forceDetach">Optional parameter that, if true, forces all action effects to detach, even those that don't want to.</param>
        /// <remarks>The actual detachment is up to the <see cref="IActionEffect"/> itself.</remarks>
        void DetachAllActionEffects(bool forceDetach = false);
    }
}
